package controller

import (
	"errors"
	"fmt"
	"gitee.com/saxon134/go-utils/saData"
	"gitee.com/saxon134/go-utils/saData/saError"
	"gitee.com/saxon134/go-utils/saData/saTime"
	"gitee.com/saxon134/go-utils/saHttp"
	"gitee.com/saxon134/workflow/api"
	"gitee.com/saxon134/workflow/conf"
	"gitee.com/saxon134/workflow/db"
	"gitee.com/saxon134/workflow/db/menu"
	"gitee.com/saxon134/workflow/db/user"
	"gitee.com/saxon134/workflow/enum"
	"gitee.com/saxon134/workflow/errs"
	"gitee.com/saxon134/workflow/interface/ioMenu"
	"gitee.com/saxon134/workflow/interface/ioUser"
	"sort"
)

func UserLogin(c *api.Context) (resp *api.Response, err error) {
	in := new(ioUser.LoginRequest)
	c.Bind(in)
	if in.Account == "" || in.Password == "" {
		return nil, errs.ErrorParams
	}

	var accObj = new(user.TblUser)
	err = db.MySql.Table(user.TBNUser).
		Where("account = ?", in.Account).
		Where("status = ?", int(enum.Enable)).
		First(accObj).Error
	if db.MySql.IsError(err) {
		return nil, saError.StackError(err)
	}

	if accObj.Id <= 0 {
		return nil, errors.New("账户不存在")
	}

	in.Password = saData.Md5("workflow"+in.Password, true)
	if in.Password != accObj.Password {
		return nil, errors.New("账户、密码不匹配")
	}

	var resObj = ioUser.LoginResponse{
		Id:       accObj.Id,
		CreateAt: accObj.CreateAt,
		Name:     accObj.Name,
		Account:  accObj.Account,
		Roles:    saData.IdsToAry(accObj.Roles),
		Token:    "",
	}

	resObj.Token, _ = saHttp.JwtGenerate(&api.AccountJwt{Id: accObj.Id}, conf.Conf.Http.JwtSecret)
	if resObj.Token == "" {
		return nil, saError.NewError("生成token失败")
	}
	return &api.Response{Result: resObj}, nil
}

func UserSave(c *api.Context) (resp *api.Response, err error) {
	in := new(ioUser.AccountSaveRequest)
	c.Bind(in)
	if in.Account.Account == "" || in.Name == "" || in.Roles == "" {
		return nil, errs.New(errs.ErrorParams)
	}

	if in.Status == 0 {
		in.Status = enum.Enable
	}

	if in.Id == 0 && in.Password == "" {
		return nil, errs.New(errs.ErrorParams)
	}

	var obj = new(user.TblUser)
	err = db.MySql.Table(user.TBNUser).
		Where("account = ?", in.Account.Account).
		First(obj).Error
	if db.MySql.IsError(err) {
		return nil, errs.New(err)
	}

	if obj.Id > 0 && in.Id <= 0 {
		return nil, errs.New("账户已存在")
	}

	if obj.Id > 0 && in.Id > 0 && obj.Id != in.Id {
		return nil, errs.New("账户名不匹配")
	}

	if obj.Id > 0 {
		if in.Password != "" {
			obj.Password = saData.Md5("ad"+in.Password, true)
		}
		obj.Name = in.Name
		obj.Status = in.Status
		obj.Roles = in.Roles
	} else {
		obj = &user.TblUser{
			Id:       0,
			CreateAt: saTime.Now(),
			Name:     in.Name,
			Account:  in.Account.Account,
			Status:   in.Status,
			Roles:    in.Roles,
		}
		obj.Password = saData.Md5("workflow"+in.Password, true)
	}
	err = db.MySql.Table(user.TBNUser).Save(obj).Error
	return &api.Response{Result: nil}, err
}

func UserModify(c *api.Context) (resp *api.Response, err error) {
	in := new(ioUser.AccountModifyRequest)
	c.Bind(in)
	if in.Id <= 0 || in.Name == "" {
		return nil, errs.New(errs.ErrorParams)
	}

	var sql = fmt.Sprintf("update user set name = '%s'", in.Name)
	if in.Password != "" {
		var password = saData.Md5("workflow"+in.Password, true)
		sql += fmt.Sprintf(", password = '%s'", password)
	}
	sql += fmt.Sprintf(" where id = %d", in.Id)
	err = db.MySql.Exec(sql).Error
	if err != nil {
		return nil, errs.New(err)
	}
	return &api.Response{Result: nil}, nil
}

func UserList(c *api.Context) (resp *api.Response, err error) {
	in := new(ioUser.ListRequest)
	c.Bind(in)

	query := db.MySql.Table(user.TBNUser)

	if in.Username != "" {
		query.Where(fmt.Sprintf("name like '%%%s%%' or account like '%%%s%%'", in.Username, in.Username))
	}

	if in.NoRole > 0 {
		query.Where("roles not like '%?%'", in.NoRole)
	}

	if c.Paging.Total <= 0 {
		query.Count(&c.Paging.Total)
	}
	if c.Paging.Total <= int64(c.Paging.Offset) {
		return &api.Response{Result: nil, Total: c.Paging.Total}, nil
	}

	var ary = make([]*user.TblUser, 0, c.Paging.Limit)
	err = query.Offset(c.Paging.Offset).Limit(c.Paging.Limit).Order("id desc").Find(&ary).Error
	if db.MySql.IsError(err) {
		return nil, saError.StackError(err)
	}

	//密码不能传递
	for _, v := range ary {
		v.Password = ""
	}
	return &api.Response{Result: ary, Total: c.Paging.Total}, nil
}

func UserMenus(c *api.Context) (resp *api.Response, err error) {
	if c.Account.Id <= 0 {
		return nil, errs.ErrorUnauthorized
	}

	var accObj = new(user.TblUser)
	db.MySql.Table(user.TBNUser).Where("id = ?", c.Account.Id).First(accObj)
	if accObj.Id <= 0 {
		return nil, errs.ErrorNotExisted
	}

	if accObj.Roles == "" {
		return nil, errs.New(errs.ErrorUnauthorized)
	}

	//所有菜单
	var allMenus = make([]*menu.TblMenu, 0, 30)
	err = db.MySql.Table(menu.TBNMenu).Find(&allMenus).Error
	if db.MySql.IsError(err) {
		return nil, saError.StackError(err)
	}
	if len(allMenus) == 0 {
		return &api.Response{Result: nil}, nil
	}

	//菜单权限筛选
	var ary = make([]*menu.TblMenu, 0, len(allMenus))
	for _, m := range allMenus {
		if m.Roles == "" {
			ary = append(ary, m)
		} else {
			var role1Ary = saData.IdsToAry(m.Roles)
			var role2Ary = saData.IdsToAry(accObj.Roles)
			for _, r := range role1Ary {
				if saData.InArray(r, role2Ary) == true {
					ary = append(ary, m)
					break
				}
			}
		}
	}

	//排序
	sort.Slice(ary, func(i, j int) bool {
		return ary[i].Seq < ary[j].Seq
	})

	//组装菜单层级
	var resAry = make([]*ioMenu.Menu, 0, 10)
	for _, v := range ary {
		if v.Roles != "" {
			var isOk = false
			var roles = saData.IdsToAry(v.Roles)
			for _, r := range roles {
				var ids = saData.IdsToAry(accObj.Roles)
				for _, r2 := range ids {
					if r == r2 {
						isOk = true
						break
					}
				}
				if isOk {
					break
				}
			}

			if isOk == false {
				continue
			}
		}

		if v.Pid == 0 {
			var m = &ioMenu.Menu{TblMenu: v}

			//查找子菜单
			m.Children = make([]*ioMenu.Menu, 0, 5)
			for _, v2 := range ary {
				if v2.Pid == v.Id {
					m.Children = append(m.Children, &ioMenu.Menu{TblMenu: v2})
				}
			}

			resAry = append(resAry, m)
		}
	}

	return &api.Response{Result: resAry}, nil
}
